```vue
<template>
  <div class="carousel">
    <div class="slides">
      <div
        v-for="(img, index) in images"
        :key="index"
        :class="['slide', { active: currentIndex === index }]"
      >
        <img :src="img" alt="汉中风景" />
      </div>
    </div>
    <div class="dots">
      <span
        v-for="(img, index) in images"
        :key="index"
        :class="{ active: currentIndex === index }"
        @click="currentIndex = index"
      ></span>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    images: { type: Array, required: true, default: () => [] }
  },
  data() {
    return {
      currentIndex: 0
    }
  },
  mounted() {
    this.startAutoPlay()
  },
  beforeUnmount() {
    clearInterval(this.autoPlayTimer)
  },
  methods: {
    startAutoPlay() {
      this.autoPlayTimer = setInterval(() => {
        this.currentIndex = (this.currentIndex + 1) % this.images.length
      }, 3000)
    }
  }
}
</script>

<style scoped>
.carousel {
  position: relative;
  max-width: 1200px;
  margin: 0 auto;
  height: 400px;
}
.slides {
  height: 100%;
}
.slide {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 0.5s ease;
}
.slide.active {
  opacity: 1;
}
.slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.dots {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 10px;
}
.dots span {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: rgba(255,255,255,0.5);
  cursor: pointer;
}
.dots span.active {
  background: white;
}
</style>